package org.qiuer.run;

import org.qiuer.ast.expression.IExpression;
import org.qiuer.ast.expression.function.Function;
import org.qiuer.func.AMemberFunction;
import org.qiuer.func.ANormalFunction;
import org.qiuer.run.Context;
import org.qiuer.exception.Const;
import org.qiuer.exception.ERuntime;
import org.qiuer.exception.IException;
import org.reflections.Reflections;

import java.util.*;

public class FunctionRegistrar {
  private static Map<String, ANormalFunction> normalFunctionMap = new HashMap<>();
  private static Map<Class, LinkedList<AMemberFunction>> memberFunctionMap = new HashMap<>();
  static {
    try {
      // 全局函数
      Reflections reflections = new Reflections(ANormalFunction.class.getPackage().getName());//不写包名也可以，但会扫描所有的包，初次加载很慢。
      Set<Class<? extends ANormalFunction>> registerClasses = reflections.getSubTypesOf(ANormalFunction.class);
      for (Class<? extends ANormalFunction> clazz : registerClasses) {
        ANormalFunction function = clazz.newInstance();
        ANormalFunction f = normalFunctionMap.put(function.getName(), function);
        if (f != null)
          System.out.println("[Warning]: 函数注册出现重名："+ f.getName());
      }

      // 成员函数
      reflections = new Reflections(AMemberFunction.class.getPackage().getName());//不写包名也可以，但会扫描所有的包，初次加载很慢。
      Set<Class<? extends AMemberFunction>> registerClasses2 = reflections.getSubTypesOf(AMemberFunction.class);
      for (Class<? extends AMemberFunction> clazz : registerClasses2) {
        AMemberFunction function = clazz.newInstance();
        LinkedList<AMemberFunction> list = memberFunctionMap.get(function.getMemberClass());
        if (list == null)
          list = new LinkedList<>();
          memberFunctionMap.put(function.getMemberClass(), list);
        list.addFirst(function);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static AMemberFunction getMemberFunction(Class clazz, String name) throws ERuntime {
    for(Map.Entry<Class, LinkedList<AMemberFunction>> entrySet: memberFunctionMap.entrySet()){
      if ((entrySet.getKey().isAssignableFrom(clazz))){
        LinkedList<AMemberFunction> list = entrySet.getValue();
        for (AMemberFunction f: list){
          if (f.getName().equals(name))
            return f;
        }
      }
    }
    throw new ERuntime(Const.EXCEPTION.UNDEFINED_FUNCTION, clazz.getSimpleName() + "未定义成员函数：" + name);
  }

  public static ANormalFunction getNormalFunction(String name) throws ERuntime {
    return normalFunctionMap.get(name);
  }

  /**
   * CallExpression 的arguments，是个Expression。是运行时调用参数。表达式执行的结果即可。
   * 注意和Function的params（Pattern）区分开。params只是定义入参。还并未到运行时。
   * @param context
   * @param arguments
   * @return
   * @throws IException
   */
  public static Object[] prepareParams(Context context, List<IExpression> arguments) throws IException {
    Object[] args = new Object[arguments.size()];
    int index = 0;
    for (IExpression expr: arguments){
      if (expr instanceof Function) //list.forEach()函数作为入参。
        args[index] = expr;
      else
        args[index] = expr.run(context);
      index++;
    }
    return args;
  }
}
